﻿@using Microsoft.FluentUI.AspNetCore.Components
@using eShopSupport.ServiceDefaults.Clients.Backend
@inject IJSRuntime JS
@inject StaffBackendClient Backend

<div class="messages-scroller">
    <div class="messages">
        @if (messages.Count == 0)
        {
            <div class="suggestions">
                <p>Ask me about our products, or pick a suggestion to get started.</p>
                @foreach (var suggestion in suggestions)
                {
                    <a href @onclick="@(() => ApplySuggestion(suggestion))" @onclick:preventDefault>
                        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M9.56158 3C5.41944 3 2.06158 6.35786 2.06158 10.5C2.06158 11.6329 2.31325 12.7088 2.76423 13.6734C2.5102 14.6714 2.22638 15.7842 2.03999 16.5147C1.80697 17.428 2.6294 18.2588 3.54374 18.039C4.29396 17.8587 5.44699 17.5819 6.47447 17.337C7.41678 17.7631 8.46241 18 9.56158 18C13.7037 18 17.0616 14.6421 17.0616 10.5C17.0616 6.35786 13.7037 3 9.56158 3ZM3.56158 10.5C3.56158 7.18629 6.24787 4.5 9.56158 4.5C12.8753 4.5 15.5616 7.18629 15.5616 10.5C15.5616 13.8137 12.8753 16.5 9.56158 16.5C8.60084 16.5 7.69487 16.2748 6.89161 15.8749L6.6482 15.7537L6.38368 15.8167C5.46095 16.0363 4.39489 16.2919 3.59592 16.4838C3.79467 15.7047 4.05784 14.6724 4.28601 13.7757L4.35619 13.4998L4.22568 13.2468C3.80145 12.4246 3.56158 11.4914 3.56158 10.5ZM14.5616 21.0001C12.5922 21.0001 10.8001 20.241 9.46191 18.9995C9.49511 18.9999 9.52835 19.0001 9.56163 19.0001C10.2796 19.0001 10.9768 18.911 11.6427 18.7434C12.5067 19.2254 13.5021 19.5001 14.5616 19.5001C15.5223 19.5001 16.4283 19.2748 17.2316 18.8749L17.475 18.7537L17.7395 18.8167C18.6611 19.0361 19.7046 19.2625 20.4787 19.4262C20.3037 18.6757 20.065 17.6711 19.8372 16.7757L19.767 16.4999L19.8975 16.2469C20.3217 15.4247 20.5616 14.4915 20.5616 13.5001C20.5616 11.3853 19.4676 9.52617 17.8146 8.45761C17.6363 7.73435 17.3653 7.04756 17.015 6.41052C19.9523 7.42684 22.0616 10.2171 22.0616 13.5001C22.0616 14.6332 21.8098 15.7094 21.3586 16.6741C21.6117 17.6821 21.8679 18.774 22.0304 19.4773C22.2348 20.3623 21.4554 21.1633 20.563 20.9768C19.8358 20.8248 18.6933 20.581 17.6495 20.3367C16.707 20.763 15.6611 21.0001 14.5616 21.0001Z"></path></svg>
                        @suggestion
                    </a>
                }
            </div>
        }

        @for (var i = 0; i < messages.Count; i++)
        {
            var id = $"message{i}";
            var state = messages[i]!;
            <TicketAssistantMessage @key="@id" State="@state" OnCompleted="@HandleResponseCompleted" OnSuggestedReply="@OnSuggestedReply" />
        }
    </div>
</div>

<form class="write-message @(ReplyInProgress ? "in-progress" : "")" @ref="@writeMessageElement" @onsubmit="@SendMessage">
    <FluentButton Class="stop-responding" @onclick="@StopResponding" Appearance="Appearance.Outline">Stop responding</FluentButton>
    <FluentTextArea @bind-Value="@userMessageText" Placeholder="Ask the AI assistant&hellip;" style="width: 100%; height: 100%;" />
</form>

@code {
    CancellationTokenSource? currentReplyCancellationTokenSource;
    List<MessageState> messages = new();
    ElementReference writeMessageElement;
    string? userMessageText;
    string[] suggestions = ["What does the manual say about this?", "Write a suggested reply to the customer."];

    [Parameter, EditorRequired]
    public TicketDetailsResult? Ticket { get; set; }

    [Parameter]
    public EventCallback<string> OnSuggestedReply { get; set; }

    bool ReplyInProgress => currentReplyCancellationTokenSource?.IsCancellationRequested == false;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            try
            {
                await using var module = await JS.InvokeAsync<IJSObjectReference>("import", "./Components/Pages/Ticket/TicketAssistant.razor.js");
                await module.InvokeVoidAsync("submitOnEnter", writeMessageElement);
            }
            catch (JSDisconnectedException)
            {
                // Not an error
            }
        }
    }

    void SendMessage()
    {
        if (Ticket is { } ticket && !string.IsNullOrWhiteSpace(userMessageText))
        {
            StopResponding();

            // Add the user's message to the UI
            messages.Add(new MessageState(new() { Text = userMessageText }, null, CancellationToken.None));
            userMessageText = null;

            // Submit request to backend
            currentReplyCancellationTokenSource = new CancellationTokenSource();
            var cancellationToken = currentReplyCancellationTokenSource.Token;
            var request = new AssistantChatRequest(
                ticket.ProductId,
                ticket.CustomerFullName,
                ticket.LongSummary,
                ticket.Messages.LastOrDefault(m => m.IsCustomerMessage)?.MessageText,
                messages.Select(m => m.Message).ToList());
            var responseItems = Backend.AssistantChatAsync(request, cancellationToken);

            // Add the assistant's reply to the UI
            var reply = new AssistantChatRequestMessage { IsAssistant = true, Text = string.Empty };
            messages.Add(new MessageState(reply, responseItems, cancellationToken));
        }
    }

    private void HandleResponseCompleted(MessageState state)
    {
        if (messages.LastOrDefault() == state)
        {
            currentReplyCancellationTokenSource = null;
        }

        // If it was cancelled before the response started, remove the message entirely
        // But if there was some text already, keep it
        if (string.IsNullOrEmpty(state.Message.Text))
        {
            messages.Remove(state);
        }
    }

    private void StopResponding()
    {
        currentReplyCancellationTokenSource?.Cancel();
    }

    private void ApplySuggestion(string suggestion)
    {
        userMessageText = suggestion;
        SendMessage();
    }

    public record MessageState(AssistantChatRequestMessage Message, IAsyncEnumerable<AssistantChatReplyItem>? ResponseItems, CancellationToken CancellationToken);
}
